#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
五子棋人机对弈系统 - MCTS神经网络AI实现
采用模块化设计，包含AI对弈逻辑、棋盘管理、用户交互等独立模块
"""

import copy
import math
import time
import threading
import random
from enum import Enum
from typing import Dict, List, Tuple, Optional, Set

# 常量定义
class Constants:
    BOARD_SIZE = 15
    EMPTY = 0
    BLACK = 1  # 先手
    WHITE = 2  # 后手
    WIN_LENGTH = 5  # 五子连珠
    
    # 游戏状态
    PLAYING = 0
    BLACK_WIN = 1
    WHITE_WIN = 2
    DRAW = 3

# ============== 棋盘管理模块 ==============
class BoardManager:
    """棋盘管理类，负责棋盘状态维护和基本操作"""
    def __init__(self):
        self.board = [[Constants.EMPTY for _ in range(Constants.BOARD_SIZE)] for _ in range(Constants.BOARD_SIZE)]
        self.current_player = Constants.BLACK
        self.game_status = Constants.PLAYING
        self.move_history = []
        
    def reset(self):
        """重置棋盘"""
        self.board = [[Constants.EMPTY for _ in range(Constants.BOARD_SIZE)] for _ in range(Constants.BOARD_SIZE)]
        self.current_player = Constants.BLACK
        self.game_status = Constants.PLAYING
        self.move_history = []
    
    def make_move(self, row: int, col: int) -> bool:
        """执行落子，如果成功返回True"""
        if not self.is_valid_move(row, col):
            return False
        
        self.board[row][col] = self.current_player
        self.move_history.append((row, col, self.current_player))
        
        # 检查胜负
        if self.check_win(row, col):
            self.game_status = Constants.BLACK_WIN if self.current_player == Constants.BLACK else Constants.WHITE_WIN
        elif self.is_board_full():
            self.game_status = Constants.DRAW
        
        # 切换玩家
        self.current_player = Constants.WHITE if self.current_player == Constants.BLACK else Constants.BLACK
        return True
    
    def is_valid_move(self, row: int, col: int) -> bool:
        """检查落子是否有效"""
        if not (0 <= row < Constants.BOARD_SIZE and 0 <= col < Constants.BOARD_SIZE):
            return False
        if self.board[row][col] != Constants.EMPTY:
            return False
        if self.game_status != Constants.PLAYING:
            return False
        return True
    
    def check_win(self, row: int, col: int) -> bool:
        """检查是否获胜"""
        player = self.board[row][col]
        if player == Constants.EMPTY:
            return False
        
        directions = [(0, 1), (1, 0), (1, 1), (1, -1)]  # 水平、垂直、两个对角线
        
        for dx, dy in directions:
            count = 1  # 当前位置已经有一个棋子
            
            # 正方向检查
            for i in range(1, Constants.WIN_LENGTH):
                nx, ny = row + i * dx, col + i * dy
                if not (0 <= nx < Constants.BOARD_SIZE and 0 <= ny < Constants.BOARD_SIZE) or self.board[nx][ny] != player:
                    break
                count += 1
            
            # 反方向检查
            for i in range(1, Constants.WIN_LENGTH):
                nx, ny = row - i * dx, col - i * dy
                if not (0 <= nx < Constants.BOARD_SIZE and 0 <= ny < Constants.BOARD_SIZE) or self.board[nx][ny] != player:
                    break
                count += 1
            
            if count >= Constants.WIN_LENGTH:
                return True
        
        return False
    
    def is_board_full(self) -> bool:
        """检查棋盘是否已满"""
        for row in range(Constants.BOARD_SIZE):
            for col in range(Constants.BOARD_SIZE):
                if self.board[row][col] == Constants.EMPTY:
                    return False
        return True
    
    def get_empty_positions(self) -> List[Tuple[int, int]]:
        """获取所有空位"""
        positions = []
        for row in range(Constants.BOARD_SIZE):
            for col in range(Constants.BOARD_SIZE):
                if self.board[row][col] == Constants.EMPTY:
                    positions.append((row, col))
        return positions
    
    def get_relevant_moves(self, radius: int = 3) -> List[Tuple[int, int]]:
        """获取相关落子点，限制搜索范围"""
        moves = set()
        
        # 找出所有已有棋子的位置
        for i in range(Constants.BOARD_SIZE):
            for j in range(Constants.BOARD_SIZE):
                if self.board[i][j] != Constants.EMPTY:
                    # 添加周围radius范围内的空点
                    for x in range(max(0, i-radius), min(Constants.BOARD_SIZE, i+radius+1)):
                        for y in range(max(0, j-radius), min(Constants.BOARD_SIZE, j+radius+1)):
                            if self.board[x][y] == Constants.EMPTY:
                                moves.add((x, y))
        
        # 如果棋盘为空或相关点太少，返回中心区域
        if len(moves) < 9:
            center_start = (Constants.BOARD_SIZE - 1) // 2 - 1
            center_end = (Constants.BOARD_SIZE - 1) // 2 + 2
            for i in range(center_start, center_end):
                for j in range(center_start, center_end):
                    if self.board[i][j] == Constants.EMPTY:
                        moves.add((i, j))
        
        return list(moves)
    
    def get_board_copy(self) -> List[List[int]]:
        """获取棋盘的深拷贝"""
        return copy.deepcopy(self.board)
    
    def undo_move(self) -> bool:
        """悔棋功能"""
        if not self.move_history:
            return False
        
        row, col, _ = self.move_history.pop()
        self.board[row][col] = Constants.EMPTY
        self.current_player = Constants.BLACK if self.current_player == Constants.WHITE else Constants.WHITE
        self.game_status = Constants.PLAYING
        return True

# ============== MCTS核心模块 ==============
class MCTSNode:
    """MCTS节点类"""
    def __init__(self, board: List[List[int]], player: int, parent=None, move: Tuple[int, int] = None):
        self.board = copy.deepcopy(board)
        self.player = player
        self.parent = parent
        self.move = move
        self.children = []
        self.visits = 0
        self.wins = 0
        self.untried_moves = self._get_untried_moves()
    
    def _get_untried_moves(self) -> List[Tuple[int, int]]:
        """获取未尝试的落子点"""
        moves = []
        for i in range(Constants.BOARD_SIZE):
            for j in range(Constants.BOARD_SIZE):
                if self.board[i][j] == Constants.EMPTY:
                    moves.append((i, j))
        return moves
    
    def is_fully_expanded(self) -> bool:
        """检查节点是否完全扩展"""
        return len(self.untried_moves) == 0
    
    def is_terminal(self) -> bool:
        """检查节点是否为终局节点"""
        # 检查胜负
        for i in range(Constants.BOARD_SIZE):
            for j in range(Constants.BOARD_SIZE):
                if self.board[i][j] != Constants.EMPTY and self._check_line_win(i, j):
                    return True
        
        # 检查是否平局
        for row in self.board:
            if Constants.EMPTY in row:
                return False
        return True
    
    def _check_line_win(self, row: int, col: int) -> bool:
        """检查以(row, col)为起点的四个方向是否有五子连珠"""
        player = self.board[row][col]
        directions = [(0, 1), (1, 0), (1, 1), (1, -1)]
        
        for dx, dy in directions:
            count = 1
            # 正方向
            for i in range(1, Constants.WIN_LENGTH):
                nx, ny = row + i * dx, col + i * dy
                if not (0 <= nx < Constants.BOARD_SIZE and 0 <= ny < Constants.BOARD_SIZE) or self.board[nx][ny] != player:
                    break
                count += 1
            # 反方向
            for i in range(1, Constants.WIN_LENGTH):
                nx, ny = row - i * dx, col - i * dy
                if not (0 <= nx < Constants.BOARD_SIZE and 0 <= ny < Constants.BOARD_SIZE) or self.board[nx][ny] != player:
                    break
                count += 1
            
            if count >= Constants.WIN_LENGTH:
                return True
        return False
    
    def expand(self) -> 'MCTSNode':
        """扩展节点
        
        Returns:
            新创建的子节点
        """
        move = self.untried_moves.pop()
        new_board = copy.deepcopy(self.board)
        new_board[move[0]][move[1]] = self.player
        next_player = Constants.WHITE if self.player == Constants.BLACK else Constants.BLACK
        
        child_node = MCTSNode(new_board, next_player, self, move)
        self.children.append(child_node)
        return child_node
    
    def expand_strategic(self) -> 'MCTSNode':
        """策略性扩展 - 优先扩展有前景的位置
        
        Returns:
            战略优先级最高的新子节点
        """
        # 计算游戏进度
        filled_count = sum(row.count(1) + row.count(2) for row in self.board)
        total_cells = Constants.BOARD_SIZE * Constants.BOARD_SIZE
        game_progress = filled_count / total_cells
        
        # 如果没有未尝试的移动，返回常规扩展
        if not self.untried_moves:
            return self.expand()
        
        # 为所有未尝试的移动计算优先级
        move_scores = []
        for move in self.untried_moves:
            row, col = move
            priority = self._calculate_move_priority(row, col, game_progress)
            move_scores.append((-priority, move))  # 负号用于升序排列时优先取高分
        
        # 按优先级排序（升序，因为分数取负）
        move_scores.sort()
        
        # 选择优先级最高的移动
        best_score, best_move = move_scores[0]
        
        # 从untried_moves中移除该移动
        self.untried_moves.remove(best_move)
        
        # 创建新的子节点
        new_board = copy.deepcopy(self.board)
        new_board[best_move[0]][best_move[1]] = self.player
        next_player = Constants.WHITE if self.player == Constants.BLACK else Constants.BLACK
        
        child_node = MCTSNode(new_board, next_player, self, best_move)
        self.children.append(child_node)
        return child_node
    
    def _calculate_move_priority(self, row: int, col: int, game_progress: float) -> float:
        """计算移动优先级
        
        Args:
            row, col: 落子位置
            game_progress: 游戏进度
            
        Returns:
            优先级分数
        """
        priority = 0
        
        # 计算位置优先级
        center = Constants.BOARD_SIZE // 2
        distance = max(abs(row - center), abs(col - center))
        
        # 游戏早期更重视中心位置
        if game_progress < 0.3:
            priority += max(0, 100 - distance * 10)
        
        # 检查邻近棋子
        nearby_count = 0
        for dx in range(-2, 3):
            for dy in range(-2, 3):
                if dx == 0 and dy == 0:
                    continue
                nx, ny = row + dx, col + dy
                if 0 <= nx < Constants.BOARD_SIZE and 0 <= ny < Constants.BOARD_SIZE:
                    if self.board[nx][ny] != Constants.EMPTY:
                        nearby_count += 1
        
        # 邻近棋子越多优先级越高
        priority += nearby_count * 20
        
        # 避免边缘和角落
        if (row <= 1 or row >= Constants.BOARD_SIZE - 2 or 
            col <= 1 or col >= Constants.BOARD_SIZE - 2):
            priority -= 50
        
        if ((row <= 0 and col <= 0) or 
            (row <= 0 and col >= Constants.BOARD_SIZE - 1) or 
            (row >= Constants.BOARD_SIZE - 1 and col <= 0) or 
            (row >= Constants.BOARD_SIZE - 1 and col >= Constants.BOARD_SIZE - 1)):
            priority -= 100
        
        return priority
    
    def rollout(self) -> int:
        """优化版模拟对局直到结束，使用启发式选择落子位置"""
        # 使用浅拷贝提高性能
        temp_board = [row[:] for row in self.board]
        temp_player = self.player
        steps = 0
        max_steps = 30  # 限制模拟步数，提高效率
        
        while steps < max_steps:
            steps += 1
            
            # 获取相关落子点，而不是所有空位置
            relevant_moves = self._get_relevant_moves(temp_board)
            if not relevant_moves:
                return 0  # 平局
            
            # 使用启发式选择落子位置
            move_quality = []
            for (row, col) in relevant_moves:
                # 临时落子并评估
                temp_board[row][col] = temp_player
                score = self._evaluate_position(temp_board, (row, col), temp_player)
                temp_board[row][col] = Constants.EMPTY  # 撤销落子
                move_quality.append((score, (row, col)))
            
            # 根据分数概率性选择落子
            if move_quality:
                scores = [x[0] for x in move_quality]
                total = sum(scores)
                if total == 0:
                    row, col = random.choice(relevant_moves)
                else:
                    # 简单概率选择
                    r = random.random()
                    cumulative = 0
                    selected_move = None
                    for i, prob in enumerate([s/total for s in scores]):
                        cumulative += prob
                        if r <= cumulative:
                            selected_move = move_quality[i][1]
                            break
                    row, col = selected_move if selected_move else random.choice(relevant_moves)
            else:
                row, col = random.choice(relevant_moves)
            
            # 执行落子
            temp_board[row][col] = temp_player
            
            # 检查是否获胜
            if self._check_line_win_in_board(temp_board, row, col):
                return 1 if temp_player == self.player else -1
            
            # 切换玩家
            temp_player = Constants.WHITE if temp_player == Constants.BLACK else Constants.BLACK
        
        # 模拟步数达到上限，使用启发式评估
        return self._heuristic_evaluate(temp_board)
    
    def _get_relevant_moves(self, board) -> List[Tuple[int, int]]:
        """获取相关的落子位置，减少搜索空间"""
        moves = set()
        radius = 2
        
        # 找出所有已有棋子周围的空点
        for i in range(Constants.BOARD_SIZE):
            for j in range(Constants.BOARD_SIZE):
                if board[i][j] != Constants.EMPTY:
                    for x in range(max(0, i-radius), min(Constants.BOARD_SIZE, i+radius+1)):
                        for y in range(max(0, j-radius), min(Constants.BOARD_SIZE, j+radius+1)):
                            if board[x][y] == Constants.EMPTY:
                                moves.add((x, y))
        
        # 如果没有相关点或太少，返回中心区域
        if len(moves) < 5:
            center = Constants.BOARD_SIZE // 2
            for i in range(center-2, center+3):
                for j in range(center-2, center+3):
                    if 0 <= i < Constants.BOARD_SIZE and 0 <= j < Constants.BOARD_SIZE and board[i][j] == Constants.EMPTY:
                        moves.add((i, j))
        
        # 如果仍然没有点，返回所有空点
        if not moves:
            for i in range(Constants.BOARD_SIZE):
                for j in range(Constants.BOARD_SIZE):
                    if board[i][j] == Constants.EMPTY:
                        moves.add((i, j))
        
        return list(moves)
    
    def _evaluate_position(self, board, position, player) -> int:
        """评估特定位置的价值"""
        row, col = position
        score = 0
        directions = [(0,1), (1,0), (1,1), (1,-1)]
        
        for dx, dy in directions:
            count = 1
            
            # 正方向
            for i in range(1, 5):
                nx, ny = row + i*dx, col + i*dy
                if 0 <= nx < Constants.BOARD_SIZE and 0 <= ny < Constants.BOARD_SIZE and board[nx][ny] == player:
                    count += 1
                else:
                    break
            
            # 反方向
            for i in range(1, 5):
                nx, ny = row - i*dx, col - i*dy
                if 0 <= nx < Constants.BOARD_SIZE and 0 <= ny < Constants.BOARD_SIZE and board[nx][ny] == player:
                    count += 1
                else:
                    break
            
            # 评分规则
            if count >= 5:
                score += 100000
            elif count == 4:
                score += 10000
            elif count == 3:
                score += 1000
            elif count == 2:
                score += 100
        
        return score
    
    def _heuristic_evaluate(self, board) -> float:
        """启发式评估函数"""
        my_score = 0
        opponent_score = 0
        opponent = Constants.WHITE if self.player == Constants.BLACK else Constants.BLACK
        
        for i in range(Constants.BOARD_SIZE):
            for j in range(Constants.BOARD_SIZE):
                if board[i][j] == self.player:
                    my_score += self._evaluate_position(board, (i, j), self.player)
                elif board[i][j] == opponent:
                    opponent_score += self._evaluate_position(board, (i, j), opponent)
        
        total_score = my_score + opponent_score
        if total_score == 0:
            return 0
        
        return (my_score - opponent_score) / total_score
    
    def _check_line_win_in_board(self, board: List[List[int]], row: int, col: int) -> bool:
        """检查指定棋盘上以(row, col)为起点是否有五子连珠"""
        player = board[row][col]
        directions = [(0, 1), (1, 0), (1, 1), (1, -1)]
        
        for dx, dy in directions:
            count = 1
            # 正方向
            for i in range(1, Constants.WIN_LENGTH):
                nx, ny = row + i * dx, col + i * dy
                if not (0 <= nx < Constants.BOARD_SIZE and 0 <= ny < Constants.BOARD_SIZE) or board[nx][ny] != player:
                    break
                count += 1
            # 反方向
            for i in range(1, Constants.WIN_LENGTH):
                nx, ny = row - i * dx, col - i * dy
                if not (0 <= nx < Constants.BOARD_SIZE and 0 <= ny < Constants.BOARD_SIZE) or board[nx][ny] != player:
                    break
                count += 1
            
            if count >= Constants.WIN_LENGTH:
                return True
        return False
    
    def backpropagate(self, result: int):
        """回溯更新节点统计信息"""
        self.visits += 1
        self.wins += result
        if self.parent:
            self.parent.backpropagate(-result)  # 父节点的视角是相反的
    
    def get_uct_value(self, exploration_weight: float = 1.414, game_progress: float = 0.0) -> float:
        """高级UCT值计算
        根据游戏阶段动态调整探索与利用平衡
        
        Args:
            exploration_weight: 基础探索权重
            game_progress: 游戏进度 (0.0-1.0)
            
        Returns:
            调整后的UCT值
        """
        if self.visits == 0:
            return float('inf')
        
        win_rate = self.wins / self.visits
        
        # 根据游戏进度调整探索权重
        # 游戏早期更多探索，晚期更多利用
        adjusted_exploration = exploration_weight * (1.0 - game_progress * 0.6)
        
        # 基础探索项
        exploration = adjusted_exploration * math.sqrt(math.log(self.parent.visits) / self.visits)
        
        # 访问次数惩罚 - 减少极端情况下的反复访问
        visit_penalty = 0
        if self.visits > self.parent.visits * 0.7:  # 如果某节点访问过多
            visit_penalty = -0.05
        
        return win_rate + exploration + visit_penalty

# 高级神经网络评估器类
class NeuralNetwork:
    """神经网络评估器 - 超级增强版
    整合高级威胁评估、位置评估和战术评估的综合局面评估系统"""
    def __init__(self):
        # 使用增强版评估函数
        self.is_loaded = True
        # 评估权重配置
        self.weights = {
            'threat_weight': 0.50,      # 威胁评估权重
            'position_weight': 0.25,    # 位置评估权重
            'tactical_weight': 0.25,    # 战术评估权重
            'board_stage_factor': 1.0   # 棋盘阶段因子
        }
    
    def evaluate(self, board: List[List[int]], player: int) -> float:
        """综合局面评估
        整合威胁、位置和战术评估的高级局面价值计算
        
        Args:
            board: 当前棋盘
            player: 当前玩家
            
        Returns:
            归一化的局面评估值 (-1.0 到 1.0)
        """
        opponent = Constants.WHITE if player == Constants.BLACK else Constants.BLACK
        
        # 1. 计算棋盘阶段
        filled_count = sum(row.count(1) + row.count(2) for row in board)
        total_cells = Constants.BOARD_SIZE * Constants.BOARD_SIZE
        game_progress = filled_count / total_cells
        
        # 根据游戏阶段动态调整权重
        stage_weights = self._get_stage_adjusted_weights(game_progress)
        
        # 2. 威胁评估
        my_threat_score = 0
        opponent_threat_score = 0
        relevant_positions = self._get_relevant_positions(board)
        
        # 为每个相关位置计算威胁分数
        for row, col in relevant_positions:
            # 检查当前玩家的威胁
            temp_board = copy.deepcopy(board)
            temp_board[row][col] = player
            threat_level = self._evaluate_threat_level(temp_board, row, col)
            
            # 威胁级别对应的分数
            threat_score = self._threat_level_to_score(threat_level)
            # 位置加成
            pos_bonus = self._calculate_position_bonus(row, col, board)
            
            my_threat_score += threat_score * pos_bonus
            
            # 检查对手的威胁
            temp_board[row][col] = opponent
            threat_level = self._evaluate_threat_level(temp_board, row, col)
            threat_score = self._threat_level_to_score(threat_level)
            
            opponent_threat_score += threat_score * pos_bonus
        
        # 3. 位置评估 - 基于当前棋盘状态
        position_score = 0
        for i in range(Constants.BOARD_SIZE):
            for j in range(Constants.BOARD_SIZE):
                if board[i][j] == player:
                    position_score += self._calculate_position_bonus(i, j, board)
                elif board[i][j] == opponent:
                    position_score -= self._calculate_position_bonus(i, j, board)
        
        # 4. 战术评估
        tactical_score = 0
        for row, col in relevant_positions:
            # 计算该位置的战术价值
            tactical_value = self._calculate_tactical_value(board, row, col, player)
            tactical_score += tactical_value
        
        # 5. 综合评分
        threat_diff = (my_threat_score - opponent_threat_score) / max(1, my_threat_score + opponent_threat_score + 10)
        
        # 归一化位置和战术评分
        max_position_score = Constants.BOARD_SIZE * Constants.BOARD_SIZE * 200  # 假设的最大位置分
        max_tactical_score = len(relevant_positions) * 5000  # 假设的最大战术分
        
        normalized_position = position_score / max_position_score if max_position_score > 0 else 0
        normalized_tactical = tactical_score / max_tactical_score if max_tactical_score > 0 else 0
        
        # 应用阶段调整的权重
        final_score = (threat_diff * stage_weights['threat_weight'] +
                      normalized_position * stage_weights['position_weight'] +
                      normalized_tactical * stage_weights['tactical_weight'])
        
        # 确保分数在[-1, 1]范围内
        final_score = max(-1.0, min(1.0, final_score))
        
        return final_score
    
    def _get_stage_adjusted_weights(self, game_progress: float) -> dict:
        """根据游戏阶段调整评估权重"""
        weights = copy.deepcopy(self.weights)
        
        if game_progress < 0.2:  # 极早期
            weights['position_weight'] *= 1.5  # 更重视位置
            weights['threat_weight'] *= 0.8   # 减少威胁权重
        elif game_progress > 0.6:  # 中后期
            weights['threat_weight'] *= 1.5   # 更重视威胁
            weights['position_weight'] *= 0.8 # 减少位置权重
        
        # 归一化权重
        total = sum(weights.values())
        for key in weights:
            weights[key] /= total
        
        return weights
    
    def _get_relevant_positions(self, board: List[List[int]]) -> list:
        """获取相关位置（已有棋子周围的位置）"""
        relevant = set()
        
        # 搜索所有已有棋子周围的3x3区域
        for i in range(Constants.BOARD_SIZE):
            for j in range(Constants.BOARD_SIZE):
                if board[i][j] != Constants.EMPTY:
                    # 添加周围3x3区域
                    for dx in range(-3, 4):
                        for dy in range(-3, 4):
                            nx, ny = i + dx, j + dy
                            if (0 <= nx < Constants.BOARD_SIZE and 
                                0 <= ny < Constants.BOARD_SIZE and 
                                board[nx][ny] == Constants.EMPTY):
                                relevant.add((nx, ny))
        
        # 如果没有相关位置（空棋盘），返回中心附近的位置
        if not relevant:
            center = Constants.BOARD_SIZE // 2
            for dx in range(-1, 2):
                for dy in range(-1, 2):
                    relevant.add((center + dx, center + dy))
        
        return list(relevant)
    
    def _evaluate_threat_level(self, board: List[List[int]], row: int, col: int) -> int:
        """评估威胁级别"""
        player = board[row][col]
        if player == Constants.EMPTY:
            return 0
        
        four_open = 0  # 活四
        four_semi = 0  # 冲四
        three_open = 0  # 活三
        three_semi = 0  # 冲三
        two_open = 0   # 活二
        two_semi = 0   # 半活二
        
        # 四个方向检查
        directions = [(0, 1), (1, 0), (1, 1), (1, -1)]
        
        for dx, dy in directions:
            # 检查正向
            line_threat = self._analyze_line_threat(board, row, col, dx, dy, player)
            four_open += line_threat['four_open']
            four_semi += line_threat['four_semi']
            three_open += line_threat['three_open']
            three_semi += line_threat['three_semi']
            two_open += line_threat['two_open']
            two_semi += line_threat['two_semi']
        
        # 计算总威胁数
        total_threats = four_open + four_semi + three_open + three_semi + two_open + two_semi
        
        # 威胁等级判定 - 更精确的威胁级别评估
        if four_open >= 1 or four_semi >= 2:  # 活四或双冲四
            return 9
        elif four_semi >= 1:  # 冲四
            return 8
        elif three_open >= 2:  # 双三
            return 7
        elif three_open >= 1 and (three_semi >= 1 or two_open >= 1):  # 活三+冲三或活三+活二
            return 6
        elif three_open >= 1:  # 活三
            return 5
        elif three_semi >= 2:  # 双冲三
            return 4
        elif three_semi >= 1:  # 冲三
            return 3
        elif two_open >= 2:  # 双活二
            return 2
        elif two_open >= 1 or two_semi >= 1:  # 活二或半活二
            return 1
        else:
            return 0
    
    def _analyze_line_threat(self, board: List[List[int]], row: int, col: int, 
                            dx: int, dy: int, player: int) -> dict:
        """分析一条直线上的威胁类型"""
        result = {
            'four_open': 0, 'four_semi': 0,
            'three_open': 0, 'three_semi': 0,
            'two_open': 0, 'two_semi': 0
        }
        
        # 统计连续的己方棋子数量和两端情况
        count = 1  # 当前位置已有一个棋子
        left_blocked = False
        right_blocked = False
        left_empty = False
        right_empty = False
        
        # 向左/上方向检查
        for i in range(1, 5):
            nx, ny = row - dx * i, col - dy * i
            if not (0 <= nx < Constants.BOARD_SIZE and 0 <= ny < Constants.BOARD_SIZE):
                left_blocked = True
                break
            if board[nx][ny] == player:
                count += 1
            elif board[nx][ny] == Constants.EMPTY:
                left_empty = True
                break
            else:
                left_blocked = True
                break
        
        # 向右/下方向检查
        for i in range(1, 5):
            nx, ny = row + dx * i, col + dy * i
            if not (0 <= nx < Constants.BOARD_SIZE and 0 <= ny < Constants.BOARD_SIZE):
                right_blocked = True
                break
            if board[nx][ny] == player:
                count += 1
            elif board[nx][ny] == Constants.EMPTY:
                right_empty = True
                break
            else:
                right_blocked = True
                break
        
        # 根据连续数量和两端情况判断威胁类型
        if count >= 5:
            # 五子连珠，但这里应该不会出现，因为在其他地方会先检测
            pass
        elif count == 4:
            if not left_blocked and not right_blocked:
                result['four_open'] = 1  # 活四
            elif not left_blocked or not right_blocked:
                result['four_semi'] = 1  # 冲四
        elif count == 3:
            if not left_blocked and not right_blocked:
                result['three_open'] = 1  # 活三
            elif not left_blocked or not right_blocked:
                result['three_semi'] = 1  # 冲三
        elif count == 2:
            if not left_blocked and not right_blocked:
                result['two_open'] = 1  # 活二
            elif not left_blocked or not right_blocked:
                result['two_semi'] = 1  # 半活二
        
        return result
    
    def _threat_level_to_score(self, threat_level: int) -> float:
        """将威胁级别转换为评分"""
        # 威胁级别对应的分数映射
        threat_scores = {
            0: 0,
            1: 10,    # 活二/半活二
            2: 30,    # 双活二
            3: 100,   # 冲三
            4: 200,   # 双冲三
            5: 500,   # 活三
            6: 800,   # 活三+冲三/活三+活二
            7: 1500,  # 双三
            8: 3000,  # 冲四
            9: 10000  # 活四/双冲四
        }
        
        return threat_scores.get(threat_level, 0)
    
    def _calculate_position_bonus(self, row: int, col: int, board: List[List[int]]) -> float:
        """计算位置加成"""
        center = Constants.BOARD_SIZE // 2
        distance = max(abs(row - center), abs(col - center))
        
        # 中心位置加成
        center_bonus = max(0, 100 - distance * 10)
        
        # 边缘惩罚
        edge_penalty = 0
        if (row <= 1 or row >= Constants.BOARD_SIZE - 2 or 
            col <= 1 or col >= Constants.BOARD_SIZE - 2):
            edge_penalty = 30
        
        # 角落惩罚
        corner_penalty = 0
        if ((row <= 0 and col <= 0) or 
            (row <= 0 and col >= Constants.BOARD_SIZE - 1) or 
            (row >= Constants.BOARD_SIZE - 1 and col <= 0) or 
            (row >= Constants.BOARD_SIZE - 1 and col >= Constants.BOARD_SIZE - 1)):
            corner_penalty = 50
        
        return center_bonus - edge_penalty - corner_penalty
    
    def _calculate_tactical_value(self, board: List[List[int]], row: int, col: int, player: int) -> float:
        """计算战术价值"""
        opponent = Constants.WHITE if player == Constants.BLACK else Constants.BLACK
        value = 0
        
        # 1. 阻断价值 - 检查如果对手在此落子会形成什么威胁
        temp_board = copy.deepcopy(board)
        temp_board[row][col] = opponent
        opponent_threat = self._evaluate_threat_level(temp_board, row, col)
        
        if opponent_threat >= 8:  # 阻止冲四或更高级威胁
            value += 5000
        elif opponent_threat >= 7:  # 阻止双三
            value += 2000
        elif opponent_threat >= 5:  # 阻止活三
            value += 1000
        
        # 2. 连接价值 - 检查能否连接己方棋子
        temp_board[row][col] = player
        connected_groups = 0
        
        for dx, dy in [(0, 1), (1, 0), (1, 1), (1, -1)]:
            has_left = False
            has_right = False
            
            # 检查左侧
            nx, ny = row - dx, col - dy
            if 0 <= nx < Constants.BOARD_SIZE and 0 <= ny < Constants.BOARD_SIZE:
                if temp_board[nx][ny] == player:
                    has_left = True
            
            # 检查右侧
            nx, ny = row + dx, col + dy
            if 0 <= nx < Constants.BOARD_SIZE and 0 <= ny < Constants.BOARD_SIZE:
                if temp_board[nx][ny] == player:
                    has_right = True
            
            if has_left and has_right:
                connected_groups += 1
        
        # 连接价值
        if connected_groups >= 2:
            value += 1500
        elif connected_groups >= 1:
            value += 500
        
        return value

# MCTS搜索引擎类
class MCTSEngine:
    """MCTS搜索引擎"""
    def __init__(self, neural_network: NeuralNetwork):
        self.neural_network = neural_network
    
    def select_best_child(self, node: MCTSNode, game_progress: float = 0.0) -> MCTSNode:
        """选择评分最高的子节点，使用阶段感知的UCT
        
        Args:
            node: 当前节点
            game_progress: 游戏进度
            
        Returns:
            最佳子节点
        """
        best_child = None
        best_value = -float('inf')
        
        for child in node.children:
            uct_value = child.get_uct_value(game_progress=game_progress)
            
            # 游戏后期更重视胜率
            if game_progress > 0.7:
                # 增加胜率权重
                win_rate = child.wins / max(1, child.visits)
                uct_value = 0.7 * uct_value + 0.3 * win_rate
            
            if uct_value > best_value:
                best_value = uct_value
                best_child = child
        
        return best_child or node.children[0]  # 防止空列表
    
    def tree_policy(self, node: MCTSNode) -> MCTSNode:
        """增强树策略：智能选择、定向扩展、阶段感知模拟"""
        # 计算游戏进度以调整策略
        filled_count = sum(row.count(1) + row.count(2) for row in node.board)
        total_cells = Constants.BOARD_SIZE * Constants.BOARD_SIZE
        game_progress = filled_count / total_cells
        
        # 阶段感知搜索
        while not node.is_terminal():
            # 定向扩展逻辑 - 优先扩展有前途的节点
            if not node.is_fully_expanded():
                # 游戏早期更激进地扩展
                if game_progress < 0.3 and node.visits > 5:  # 足够访问后再扩展
                    # 检查节点是否有expand_strategic方法
                    if hasattr(node, 'expand_strategic'):
                        return node.expand_strategic()
                    else:
                        return node.expand()
                else:
                    return node.expand()
            else:
                # 使用阶段感知的UCT
                node = self.select_best_child(node, game_progress)
        return node
    
    def search(self, board: List[List[int]], player: int, num_simulations: int = 1000) -> Tuple[int, int]:
        """执行MCTS搜索，返回最佳落子位置"""
        root = MCTSNode(board, player)
        
        for _ in range(num_simulations):
            # 选择和扩展
            promising_node = self.tree_policy(root)
            
            # 模拟（结合神经网络评估）
            if promising_node.is_terminal():
                # 如果是终局节点，直接获取结果
                # 检查谁赢了
                winner = None
                for i in range(Constants.BOARD_SIZE):
                    for j in range(Constants.BOARD_SIZE):
                        if promising_node.board[i][j] != Constants.EMPTY:
                            if promising_node._check_line_win(i, j):
                                winner = promising_node.board[i][j]
                                break
                    if winner:
                        break
                
                if winner:
                    result = 1 if winner == player else -1
                else:
                    result = 0  # 平局
                promising_node.backpropagate(result)
            else:
                # 使用神经网络评估局面
                nn_value = self.neural_network.evaluate(promising_node.board, promising_node.player)
                promising_node.backpropagate(nn_value)
        
        # 返回访问次数最多的子节点
        if root.children:
            best_child = max(root.children, key=lambda child: child.visits)
            # 确保返回的坐标在有效范围内
            row, col = best_child.move
            row = max(0, min(row, Constants.BOARD_SIZE - 1))
            col = max(0, min(col, Constants.BOARD_SIZE - 1))
            return (row, col)
        
        # 如果没有子节点，返回中心位置
        center = Constants.BOARD_SIZE // 2
        return (center, center)

# 并行MCTS类
class ParallelMCTS:
    """并行MCTS搜索引擎"""
    def __init__(self, neural_network: NeuralNetwork, num_threads: int = 4):
        self.neural_network = neural_network
        self.num_threads = num_threads
        self.lock = threading.Lock()
    
    def _worker_thread(self, root_node: MCTSNode, num_simulations: int):
        """工作线程函数"""
        engine = MCTSEngine(self.neural_network)
        
        for _ in range(num_simulations):
            # 克隆根节点以避免线程间的冲突
            with self.lock:
                node = copy.deepcopy(root_node)
            
            # 选择和扩展
            promising_node = engine.tree_policy(node)
            
            # 模拟
            if promising_node.is_terminal():
                # 检查终局结果
                for i in range(Constants.BOARD_SIZE):
                    for j in range(Constants.BOARD_SIZE):
                        if promising_node.board[i][j] != Constants.EMPTY:
                            if promising_node._check_line_win(i, j):
                                result = 1 if promising_node.board[i][j] == root_node.player else -1
                                break
                    else:
                        continue
                    break
                else:
                    result = 0  # 平局
            else:
                result = self.neural_network.evaluate(promising_node.board, promising_node.player)
            
            # 回溯（需要加锁）
            with self.lock:
                promising_node.backpropagate(result)
    
    def search(self, board: List[List[int]], player: int, num_simulations: int = 1000) -> Tuple[int, int]:
        """并行执行MCTS搜索"""
        root_node = MCTSNode(board, player)
        
        # 线程分配
        simulations_per_thread = num_simulations // self.num_threads
        threads = []
        
        for i in range(self.num_threads):
            # 最后一个线程处理剩余的模拟
            sims = simulations_per_thread + (num_simulations % self.num_threads) if i == self.num_threads - 1 else simulations_per_thread
            t = threading.Thread(target=self._worker_thread, args=(root_node, sims))
            threads.append(t)
            t.start()
        
        # 等待所有线程完成
        for t in threads:
            t.join()
        
        # 返回最佳移动
        if root_node.children:
            best_child = max(root_node.children, key=lambda child: child.visits)
            # 确保返回的坐标在有效范围内
            row, col = best_child.move
            row = max(0, min(row, Constants.BOARD_SIZE - 1))
            col = max(0, min(col, Constants.BOARD_SIZE - 1))
            return (row, col)
        
        # 如果没有子节点，返回中心位置
        center = Constants.BOARD_SIZE // 2
        return (center, center)

# ============== AI玩家模块 ==============
class AIDifficulty(Enum):
    """AI难度枚举"""
    EASY = 1
    MEDIUM = 2
    HARD = 3
    EXPERT = 4
    MASTER = 5

class AIPlayer:
    """AI玩家类"""
    def __init__(self, difficulty: AIDifficulty = AIDifficulty.MEDIUM):
        self.difficulty = difficulty
        self.neural_network = NeuralNetwork()
        # 根据难度设置参数
        self.difficulty_config = {
            AIDifficulty.EASY: {
                'num_simulations': 100,
                'use_parallel': False,
                'thinking_time': 0.5
            },
            AIDifficulty.MEDIUM: {
                'num_simulations': 300,
                'use_parallel': True,
                'thinking_time': 1.0,
                'num_threads': 2
            },
            AIDifficulty.HARD: {
                'num_simulations': 500,
                'use_parallel': True,
                'thinking_time': 1.5,
                'num_threads': 2
            },
            AIDifficulty.EXPERT: {
                'num_simulations': 1000,
                'use_parallel': True,
                'thinking_time': 2.0,
                'num_threads': 4
            },
            AIDifficulty.MASTER: {
                'num_simulations': 2000,
                'use_parallel': True,
                'thinking_time': 3.0,
                'num_threads': 4
            }
        }
        
        self.config = self.difficulty_config[difficulty]
    
    def set_difficulty(self, difficulty: AIDifficulty):
        """设置AI难度"""
        self.difficulty = difficulty
        self.config = self.difficulty_config[difficulty]
    
    def find_best_move(self, board: List[List[int]], player: int) -> Tuple[int, int]:
        """寻找最佳落子位置，优化版"""
        # 首先检查是否有直接获胜或阻止对方获胜的关键落子点（性能优先）
        critical_move = self._check_critical_moves(board, player)
        if critical_move:
            return critical_move
        
        # 优化搜索策略
        # 创建棋盘管理器用于获取相关落子点
        temp_board_manager = BoardManager()
        temp_board_manager.board = copy.deepcopy(board)
        
        # 根据配置选择搜索引擎
        if self.config['use_parallel']:
            engine = ParallelMCTS(self.neural_network, self.config.get('num_threads', 2))
        else:
            engine = MCTSEngine(self.neural_network)
        
        # 执行搜索，使用更少但更相关的模拟次数
        start_time = time.time()
        # 随着游戏进行动态调整模拟次数 - 修复逻辑：游戏后期增加模拟次数
        # 计算已落子比例
        filled_cells = sum(row.count(1) + row.count(2) for row in board)
        total_cells = Constants.BOARD_SIZE * Constants.BOARD_SIZE
        game_progress = filled_cells / total_cells  # 范围从0到1
        
        # 游戏初期(progress<0.3)：使用基础模拟次数的70%，快速响应
        # 中期(0.3<=progress<0.6)：使用基础模拟次数
        # 后期(progress>=0.6)：最多增加到基础模拟次数的150%，确保重要决策质量
        if game_progress < 0.3:
            adjusted_simulations = max(50, int(self.config['num_simulations'] * 0.7))  # 最少50次
        elif game_progress < 0.6:
            adjusted_simulations = self.config['num_simulations']
        else:
            adjusted_simulations = min(self.config['num_simulations'] * 2, 
                                      int(self.config['num_simulations'] * (1 + game_progress * 0.5)))
        
        best_move = engine.search(board, player, adjusted_simulations)
        
        # 确保思考时间（为了用户体验）
        elapsed_time = time.time() - start_time
        remaining_time = self.config['thinking_time'] - elapsed_time
        if remaining_time > 0:
            time.sleep(remaining_time)
        
        return best_move
    
    def _check_critical_moves(self, board: List[List[int]], player: int) -> Optional[Tuple[int, int]]:
        """高级威胁检测系统 - 终极版
        增强威胁检测的精确性、决策质量和战略思考能力
        
        Args:
            board: 当前棋盘
            player: 当前玩家
            
        Returns:
            最佳关键落子位置或None
        """
        opponent = Constants.WHITE if player == Constants.BLACK else Constants.BLACK
        
        # 阶段1: 扩大搜索范围，确保不遗漏关键威胁
        critical_positions = self._get_expanded_relevant_positions(board)
        
        # 阶段2: 多维度威胁评估和战略决策 - 增强版
        moves_evaluation = []
        immediate_win_moves = []  # 记录可立即获胜的位置
        immediate_defense_moves = []  # 记录必须防守的位置
        
        # 特殊处理：棋盘早期，优先考虑中心和战略位置
        filled_cells = sum(row.count(1) + row.count(2) for row in board)
        is_early_game = filled_cells < 10
        
        for i, j in critical_positions:
            # 复制棋盘进行模拟评估，避免修改原棋盘
            test_board = copy.deepcopy(board)
            
            # 1. 评估当前玩家在此位置落子后的综合威胁情况
            test_board[i][j] = player
            my_threat_level = self._evaluate_threat_level(test_board, i, j)
            
            # 2. 评估对手在此位置落子后的综合威胁情况
            test_board[i][j] = opponent
            opponent_threat_level = self._evaluate_threat_level(test_board, i, j)
            
            # 重置棋盘，获取详细威胁信息
            test_board[i][j] = player
            my_threat_details = self._get_threat_details(test_board, i, j, player)
            
            test_board[i][j] = opponent
            opponent_threat_details = self._get_threat_details(test_board, i, j, opponent)
            
            # 阶段3: 立即处理必胜或必防的情况 - 优化版本
            # 最高优先级：己方直接胜利（活四或更高）
            if my_threat_level >= 9:
                return (i, j)  # 立即返回，不需要进一步考虑
            
            # 记录潜在的胜利和防守位置
            if my_threat_level == 8:  # 冲四
                immediate_win_moves.append((i, j))
            
            # 次高优先级：阻止对手直接胜利
            if opponent_threat_level >= 9:
                return (i, j)  # 必须立即防守
            
            # 记录必须防守的位置
            if opponent_threat_level == 8:  # 对手冲四
                immediate_defense_moves.append((i, j))
            
            # 特殊情况：黑棋双三（根据规则，黑棋不能主动形成双三，但可以防守）
            if player == Constants.WHITE and opponent_threat_level == 6:  # 防守对手黑棋双三
                immediate_defense_moves.append((i, j))
            
            # 阶段4: 计算综合战略评分 - 增强版
            # 4.1 威胁级别基础评分
            base_score = self._calculate_base_threat_score(my_threat_level, opponent_threat_level)
            
            # 4.2 威胁组合评分（处理多威胁情况）
            combo_score = self._calculate_threat_combo_score(
                my_threat_details, opponent_threat_details, player
            )
            
            # 4.3 位置价值评分 - 优化版
            position_score = self._calculate_advanced_position_score(i, j, board)
            
            # 4.4 战术评分（评估该位置的战略意义）
            tactical_score = self._calculate_tactical_score(board, i, j, player)
            
            # 4.5 游戏阶段调整 - 更智能的评分调整
            phase_adjustment = 0
            center = Constants.BOARD_SIZE // 2
            distance_to_center = max(abs(i - center), abs(j - center))
            
            if is_early_game:
                # 游戏早期，中心区域权重更高
                phase_adjustment = (10 - distance_to_center) * 20
                # 避免过早靠近边缘
                if distance_to_center > 7:
                    phase_adjustment -= 100
            else:
                # 游戏中后期，威胁权重更高
                if my_threat_level >= 4 or opponent_threat_level >= 4:
                    phase_adjustment = 100
            
            # 4.6 潜在威胁分析 - 新增
            potential_threat_bonus = 0
            # 检查该位置是否能同时形成多个方向的威胁
            if my_threat_details['total_threats'] >= 2:
                potential_threat_bonus += 150
            
            # 4.7 综合评分
            total_score = (base_score + combo_score + position_score + 
                         tactical_score + phase_adjustment + potential_threat_bonus)
            
            # 黑棋特殊规则处理
            if player == Constants.BLACK and my_threat_level == 6:  # 黑棋双三
                total_score += 800  # 提高黑棋双三的优先级
            
            # 添加到评估列表
            moves_evaluation.append((total_score, i, j))
        
        # 处理立即行动的情况
        if immediate_win_moves:  # 优先考虑冲四获胜
            return immediate_win_moves[0]
        
        if immediate_defense_moves:  # 其次考虑防守对手冲四
            return immediate_defense_moves[0]
        
        # 阶段5: 智能排序和选择 - 增强版
        if moves_evaluation:
            # 按综合评分降序排序
            moves_evaluation.sort(reverse=True, key=lambda x: x[0])
            
            # 考虑更多候选位置进行深入分析
            top_count = min(5, len(moves_evaluation))  # 考虑前5个选择
            top_moves = moves_evaluation[:top_count]
            
            # 对前几个选项进行更深入的评估和验证
            best_move = self._select_best_move_from_candidates(board, top_moves, player)
            return best_move
        
        # 如果没有找到合适的关键位置，返回中心点附近
        center = Constants.BOARD_SIZE // 2
        for radius in range(0, 5):  # 从中心向外寻找空位
            for dx in range(-radius, radius + 1):
                for dy in range(-radius, radius + 1):
                    if abs(dx) == radius or abs(dy) == radius:  # 只检查当前半径的环
                        nx, ny = center + dx, center + dy
                        if (0 <= nx < Constants.BOARD_SIZE and 
                            0 <= ny < Constants.BOARD_SIZE and 
                            board[nx][ny] == Constants.EMPTY):
                            return (nx, ny)
        
        return None
    
    def _get_expanded_relevant_positions(self, board: List[List[int]]) -> set:
        """智能获取扩展的相关位置搜索区域
        基于棋子密度和位置动态确定需要评估的位置
        
        Args:
            board: 当前棋盘
            
        Returns:
            相关位置集合
        """
        relevant_positions = set()
        has_棋子 = False
        
        # 1. 获取所有已有棋子及其周围更大范围（5x5）
        for i in range(Constants.BOARD_SIZE):
            for j in range(Constants.BOARD_SIZE):
                if board[i][j] != Constants.EMPTY:
                    has_棋子 = True
                    # 扩大搜索范围到5x5
                    for dx in range(-5, 6):
                        for dy in range(-5, 6):
                            nx, ny = i + dx, j + dy
                            if (0 <= nx < Constants.BOARD_SIZE and 
                                0 <= ny < Constants.BOARD_SIZE and 
                                board[nx][ny] == Constants.EMPTY):
                                relevant_positions.add((nx, ny))
        
        # 2. 对于空棋盘或接近空的棋盘，重点关注中心区域
        if len(relevant_positions) < 10 or not has_棋子:
            center = Constants.BOARD_SIZE // 2
            # 扩大中心区域搜索范围
            for i in range(max(0, center - 6), min(Constants.BOARD_SIZE, center + 7)):
                for j in range(max(0, center - 6), min(Constants.BOARD_SIZE, center + 7)):
                    if board[i][j] == Constants.EMPTY:
                        relevant_positions.add((i, j))
        
        # 3. 对于已有一定棋子的棋盘，添加所有有潜力形成威胁的位置
        if len(relevant_positions) > 5:  # 棋盘已有一定棋子
            # 找出所有可能形成威胁的位置
            self._add_potential_threat_positions(board, relevant_positions)
        
        return relevant_positions
    
    def _add_potential_threat_positions(self, board: List[List[int]], positions: set):
        """添加所有可能形成威胁的位置
        
        Args:
            board: 当前棋盘
            positions: 位置集合（将被修改）
        """
        # 检查所有已存在的连续两子或更多的情况，添加可能形成威胁的空位
        directions = [(0, 1), (1, 0), (1, 1), (1, -1)]
        
        for i in range(Constants.BOARD_SIZE):
            for j in range(Constants.BOARD_SIZE):
                if board[i][j] != Constants.EMPTY:
                    player = board[i][j]
                    
                    for dx, dy in directions:
                        # 检查该方向上是否有连续棋子
                        count = 1
                        empty_ends = []
                        
                        # 正方向
                        nx, ny = i + dx, j + dy
                        while 0 <= nx < Constants.BOARD_SIZE and 0 <= ny < Constants.BOARD_SIZE:
                            if board[nx][ny] == player:
                                count += 1
                            elif board[nx][ny] == Constants.EMPTY:
                                empty_ends.append((nx, ny))
                                break
                            else:
                                break
                            nx += dx
                            ny += dy
                        
                        # 反方向
                        nx, ny = i - dx, j - dy
                        while 0 <= nx < Constants.BOARD_SIZE and 0 <= ny < Constants.BOARD_SIZE:
                            if board[nx][ny] == player:
                                count += 1
                            elif board[nx][ny] == Constants.EMPTY:
                                empty_ends.append((nx, ny))
                                break
                            else:
                                break
                            nx -= dx
                            ny -= dy
                        
                        # 如果有连续2子或更多，添加可能形成威胁的空位
                        if count >= 2 and empty_ends:
                            for pos in empty_ends:
                                positions.add(pos)
    
    def _get_threat_details(self, board: List[List[int]], row: int, col: int, player: int) -> dict:
        """获取详细的威胁情况分析
        
        Args:
            board: 棋盘状态
            row, col: 落子位置
            player: 玩家
            
        Returns:
            详细威胁信息字典
        """
        details = {
            'four_open': 0,   # 活四数量
            'four_semi': 0,   # 冲四数量
            'three_open': 0,  # 活三数量
            'three_semi': 0,  # 冲三数量
            'two_open': 0,    # 活二数量
            'two_semi': 0,    # 半活二数量
            'double_three': False,  # 是否有双三
            'double_four': False,   # 是否有双四
            'total_threats': 0      # 总威胁数
        }
        
        directions = [(0, 1), (1, 0), (1, 1), (1, -1)]
        threat_types = []
        
        # 检查四个方向的威胁
        for dx, dy in directions:
            # 检查该方向上的威胁类型
            left_empty = right_empty = False
            left_blocked = right_blocked = False
            left_count = right_count = 0
            
            # 正方向
            for i in range(1, 6):  # 最多检查5步
                nx, ny = row + i * dx, col + i * dy
                if not (0 <= nx < Constants.BOARD_SIZE and 0 <= ny < Constants.BOARD_SIZE):
                    right_blocked = True
                    break
                if board[nx][ny] == player:
                    right_count += 1
                elif board[nx][ny] == Constants.EMPTY:
                    right_empty = True
                    break
                else:
                    right_blocked = True
                    break
            
            # 反方向
            for i in range(1, 6):
                nx, ny = row - i * dx, col - i * dy
                if not (0 <= nx < Constants.BOARD_SIZE and 0 <= ny < Constants.BOARD_SIZE):
                    left_blocked = True
                    break
                if board[nx][ny] == player:
                    left_count += 1
                elif board[nx][ny] == Constants.EMPTY:
                    left_empty = True
                    break
                else:
                    left_blocked = True
                    break
            
            total_count = left_count + right_count + 1  # 加上当前位置
            
            # 确定威胁类型
            if total_count >= 4:
                if left_empty and right_empty:
                    details['four_open'] += 1
                    threat_types.append('four_open')
                elif left_empty or right_empty:
                    details['four_semi'] += 1
                    threat_types.append('four_semi')
            elif total_count == 3:
                if left_empty and right_empty:
                    details['three_open'] += 1
                    threat_types.append('three_open')
                elif left_empty or right_empty:
                    details['three_semi'] += 1
                    threat_types.append('three_semi')
            elif total_count == 2:
                if left_empty and right_empty:
                    details['two_open'] += 1
                    threat_types.append('two_open')
                elif left_empty or right_empty:
                    details['two_semi'] += 1
                    threat_types.append('two_semi')
        
        # 检测多威胁情况
        three_count = details['three_open'] + details['three_semi']
        four_count = details['four_open'] + details['four_semi']
        
        if three_count >= 2:
            details['double_three'] = True
        if four_count >= 2:
            details['double_four'] = True
        
        details['total_threats'] = sum(threat_types.count(t) for t in ['four_open', 'four_semi', 'three_open', 'three_semi'])
        
        return details
    
    def _calculate_base_threat_score(self, my_threat: int, opponent_threat: int) -> int:
        """计算基础威胁评分 - 超级增强版
        优化威胁级别与分数对应关系，提高AI决策的战略深度
        
        Args:
            my_threat: 己方威胁级别
            opponent_threat: 对手威胁级别
            
        Returns:
            基础评分
        """
        score = 0
        
        # 己方威胁评分 - 重新校准为更合理的战略权重
        threat_scores = {
            10: 50000,  # 五连（立即胜利）
            9: 15000,   # 活四（极高优先级）
            8: 8000,    # 冲四（高优先级）
            7: 5000,    # 双四（非常危险）
            6: 3000,    # 双三（强力进攻）
            5: 1500,    # 活三
            4: 800,     # 眠三（冲三）
            3: 400,     # 双二
            2: 200,     # 活二
            1: 50       # 其他
        }
        
        # 对手威胁评分（防守优先级）
        defense_scores = {
            10: 45000,  # 五连（紧急防守）
            9: 14000,   # 活四（极高优先级防守）
            8: 7000,    # 冲四（高优先级防守）
            7: 4500,    # 双四（必须防守）
            6: 2500,    # 双三（必须防守）
            5: 1200,    # 活三
            4: 600,     # 眠三
            3: 300,     # 双二
            2: 150,     # 活二
            1: 30       # 其他
        }
        
        # 添加攻击和防守分数
        if my_threat in threat_scores:
            score += threat_scores[my_threat]
        if opponent_threat in defense_scores:
            score += defense_scores[opponent_threat]
        
        # 战略优先级调整
        if opponent_threat >= 9 and my_threat < 8:
            # 当对手有活四或以上，防守绝对优先
            score = int(score * 1.5)
        elif my_threat >= 9:
            # 当自己有活四或以上，攻击绝对优先
            score = int(score * 1.3)
        elif my_threat >= 7 and opponent_threat < 5:
            # 自己有双四且对手威胁较低时，加强进攻
            score = int(score * 1.4)
        elif my_threat >= 5 and opponent_threat < 5:
            # 自己有活三且对手威胁较低时，加强进攻
            score = int(score * 1.2)
        
        # 威胁级别优势奖励
        threat_diff = my_threat - opponent_threat
        if threat_diff >= 2:
            score += 500  # 明显的威胁级别优势
        elif threat_diff >= 1:
            score += 200  # 威胁级别优势
        
        return score
    
    def _calculate_threat_combo_score(self, my_details: dict, opponent_details: dict, player: int) -> int:
        """计算威胁组合评分 - 超级增强版
        更全面、更精准的威胁组合评估，增强战略判断能力
        
        Args:
            my_details: 己方威胁详情
            opponent_details: 对手威胁详情
            player: 当前玩家
            
        Returns:
            组合评分
        """
        score = 0
        
        # 1. 高级攻击威胁组合 - 重新校准
        # 活四威胁
        if my_details.get('four_open', 0) >= 1:
            score += 8000  # 活四是立即获胜的前兆
        # 冲四威胁
        if my_details.get('four_semi', 0) >= 1:
            score += 4000
        # 双冲四组合
        if my_details.get('four_semi', 0) >= 2:
            score += 15000  # 双冲四是致命组合
        # 双四组合
        if my_details.get('double_four', False):
            score += 20000  # 双四几乎必胜
        # 双三组合
        if my_details.get('double_three', False):
            base_double_three = 6000
            # 黑棋双三特别加分
            if player == Constants.BLACK:
                base_double_three = 10000  # 黑棋双三是决定性优势
            score += base_double_three
        # 活三+活二组合
        if my_details.get('three_open', 0) >= 1 and my_details.get('two_open', 0) >= 1:
            score += 1500
        # 冲四+活三组合（强力组合）
        if my_details.get('four_semi', 0) >= 1 and my_details.get('three_open', 0) >= 1:
            score += 8000  # 这个组合通常能直接获胜
        # 活三+眠三组合
        if my_details.get('three_open', 0) >= 1 and my_details.get('three_semi', 0) >= 1:
            score += 3000
        # 多个活三
        if my_details.get('three_open', 0) >= 2:
            score += 5000
        # 多个活二策略价值
        if my_details.get('two_open', 0) >= 4:
            score += 2000
        elif my_details.get('two_open', 0) >= 3:
            score += 1000
        elif my_details.get('two_open', 0) >= 2:
            score += 500
        
        # 2. 高级防守威胁组合 - 重新校准
        # 防守活四
        if opponent_details.get('four_open', 0) >= 1:
            score += 7500  # 紧急防守
        # 防守冲四
        if opponent_details.get('four_semi', 0) >= 1:
            score += 3500
        # 防守双冲四
        if opponent_details.get('four_semi', 0) >= 2:
            score += 14000  # 必须立即防守双冲四
        # 防守双四
        if opponent_details.get('double_four', False):
            score += 18000  # 必须防守对手双四
        # 防守双三
        if opponent_details.get('double_three', False):
            base_defense = 5500
            # 防守黑棋双三需要特别优先
            if player == Constants.WHITE:
                base_defense = 9000  # 白棋必须优先防守黑棋双三
            score += base_defense
        # 防守活三+活二
        if opponent_details.get('three_open', 0) >= 1 and opponent_details.get('two_open', 0) >= 1:
            score += 1200
        # 防守活三+眠三
        if opponent_details.get('three_open', 0) >= 1 and opponent_details.get('three_semi', 0) >= 1:
            score += 2500
        # 防守多个活三
        if opponent_details.get('three_open', 0) >= 2:
            score += 4500
        
        # 3. 战略平衡和威胁密度评估
        # 同时具备进攻和防守价值
        my_total = my_details.get('total_threats', 0)
        opp_total = opponent_details.get('total_threats', 0)
        
        if my_total >= 1 and opp_total >= 1:
            score += 800  # 位置同时具有攻防价值
        
        # 威胁密度评估
        total_threats = (my_details.get('four_open', 0) + my_details.get('four_semi', 0) +
                        my_details.get('three_open', 0) + my_details.get('three_semi', 0) +
                        my_details.get('two_open', 0) + my_details.get('two_semi', 0))
        
        if total_threats >= 5:
            score += 3000  # 极高威胁密度
        elif total_threats >= 4:
            score += 1500
        elif total_threats >= 3:
            score += 800
        
        # 4. 威胁数量优势（更精确的计算）
        threat_diff = my_total - opp_total
        if threat_diff >= 3:
            score += threat_diff * 200  # 明显优势
        elif threat_diff >= 2:
            score += threat_diff * 150
        elif threat_diff >= 1:
            score += threat_diff * 100
        
        # 5. 特殊情况：黑白棋策略差异
        # 白棋需要更强的防守意识
        if player == Constants.WHITE and opponent_details.get('total_threats', 0) > my_total:
            score += 500  # 白棋防守加成
        
        return score
    
    def _calculate_advanced_position_score(self, row: int, col: int, board: List[List[int]]) -> int:
        """高级位置价值评估 - 超级增强版
        更全面的位置价值计算，考虑战略中心点、棋子连贯性、威胁位置等因素
        
        Args:
            row, col: 位置坐标
            board: 当前棋盘
            
        Returns:
            位置价值评分
        """
        center = Constants.BOARD_SIZE // 2
        
        # 1. 战略中心点评分 - 重新设计权重
        distance_to_center = max(abs(row - center), abs(col - center))
        base_position_score = max(0, 200 - distance_to_center * 20)
        
        # 2. 邻近棋子评分增强版 - 考虑棋子连贯性和方向
        nearby_score = 0
        for dx, dy in [(-2, 0), (-1, 0), (1, 0), (2, 0),  # 水平方向
                       (0, -2), (0, -1), (0, 1), (0, 2),  # 垂直方向
                       (-2, -2), (-1, -1), (1, 1), (2, 2),  # 对角线
                       (-2, 2), (-1, 1), (1, -1), (2, -2)]:  # 反对角线
            nx, ny = row + dx, col + dy
            if 0 <= nx < Constants.BOARD_SIZE and 0 <= ny < Constants.BOARD_SIZE:
                if board[nx][ny] != Constants.EMPTY:
                    # 距离越近加分越多，且方向权重不同
                    dist = max(abs(dx), abs(dy))
                    direction_weight = 1.5 if dx == 0 or dy == 0 else 1.0  # 直线方向更重要
                    nearby_score += int((4 - dist) * 30 * direction_weight)
        
        # 3. 连续棋子奖励 - 新增
        continuous_bonus = 0
        for direction in [(0, 1), (1, 0), (1, 1), (1, -1)]:  # 四个方向
            dx, dy = direction
            # 检查当前方向是否有连续棋子
            count = 0
            for i in range(1, 4):  # 向前检查3步
                nx, ny = row + dx * i, col + dy * i
                if 0 <= nx < Constants.BOARD_SIZE and 0 <= ny < Constants.BOARD_SIZE:
                    if board[nx][ny] != Constants.EMPTY:
                        count += 1
                    else:
                        break
                else:
                    break
            
            for i in range(1, 4):  # 向后检查3步
                nx, ny = row - dx * i, col - dy * i
                if 0 <= nx < Constants.BOARD_SIZE and 0 <= ny < Constants.BOARD_SIZE:
                    if board[nx][ny] != Constants.EMPTY:
                        count += 1
                    else:
                        break
                else:
                    break
            
            if count >= 3:
                continuous_bonus += 200
            elif count >= 2:
                continuous_bonus += 100
            elif count >= 1:
                continuous_bonus += 50
        
        # 4. 边缘和角落位置惩罚 - 更精细的计算
        edge_penalty = 0
        corner_penalty = 0
        
        # 边缘位置惩罚
        if (row <= 2 or row >= Constants.BOARD_SIZE - 3 or 
            col <= 2 or col >= Constants.BOARD_SIZE - 3):
            edge_penalty = 150  # 边缘位置减分增加
        
        # 角落位置惩罚
        if ((row <= 1 and col <= 1) or 
            (row <= 1 and col >= Constants.BOARD_SIZE - 2) or 
            (row >= Constants.BOARD_SIZE - 2 and col <= 1) or 
            (row >= Constants.BOARD_SIZE - 2 and col >= Constants.BOARD_SIZE - 2)):
            corner_penalty = 300  # 角落位置大幅减分增加
        
        # 5. 棋盘阶段调整 - 更智能的位置价值变化
        filled_count = sum(row.count(1) + row.count(2) for row in board)
        stage_adjustment = 0
        
        if filled_count < 8:  # 极早期
            # 极早期非常重视中心
            stage_adjustment = (10 - distance_to_center) * 30
            # 避免极早期靠近边缘
            if distance_to_center > 6:
                stage_adjustment -= 200
        elif filled_count < 20:  # 早期
            # 早期重视中心，但可以适当扩展
            stage_adjustment = (8 - distance_to_center) * 20
        elif filled_count < 40:  # 中期
            # 中期平衡中心和威胁区域
            # 检查是否靠近现有棋子群
            nearby_filled = 0
            for dx in range(-3, 4):
                for dy in range(-3, 4):
                    nx, ny = row + dx, col + dy
                    if 0 <= nx < Constants.BOARD_SIZE and 0 <= ny < Constants.BOARD_SIZE:
                        if board[nx][ny] != Constants.EMPTY:
                            nearby_filled += 1
            
            if nearby_filled >= 5:  # 靠近棋子群
                stage_adjustment = 150
        else:  # 晚期
            # 晚期更重视潜在的获胜路径
            # 检查四个方向是否有发展空间
            open_directions = 0
            for direction in [(0, 1), (1, 0), (1, 1), (1, -1)]:
                dx, dy = direction
                # 检查是否有足够的开放空间
                space_count = 0
                block_count = 0
                for i in range(1, 6):
                    nx, ny = row + dx * i, col + dy * i
                    if 0 <= nx < Constants.BOARD_SIZE and 0 <= ny < Constants.BOARD_SIZE:
                        if board[nx][ny] == Constants.EMPTY:
                            space_count += 1
                        else:
                            block_count += 1
                            break
                    else:
                        break
                
                if space_count >= 3 and block_count == 0:
                    open_directions += 1
            
            stage_adjustment = open_directions * 100
            
            # 晚期可以适当考虑边缘位置
            if distance_to_center > 8 and open_directions >= 1:
                stage_adjustment += 50
        
        # 6. 战略位置奖励 - 新增
        strategic_bonus = 0
        
        # 检查是否是关键交叉点（多个威胁方向的交汇）
        threat_directions = 0
        for direction in [(0, 1), (1, 0), (1, 1), (1, -1)]:
            dx, dy = direction
            # 检查该方向是否有潜在威胁
            has_threat = False
            for i in range(1, 4):
                nx, ny = row + dx * i, col + dy * i
                if 0 <= nx < Constants.BOARD_SIZE and 0 <= ny < Constants.BOARD_SIZE:
                    if board[nx][ny] != Constants.EMPTY:
                        has_threat = True
                        break
            
            for i in range(1, 4):
                nx, ny = row - dx * i, col - dy * i
                if 0 <= nx < Constants.BOARD_SIZE and 0 <= ny < Constants.BOARD_SIZE:
                    if board[nx][ny] != Constants.EMPTY:
                        has_threat = True
                        break
            
            if has_threat:
                threat_directions += 1
        
        if threat_directions >= 3:
            strategic_bonus += 300  # 多威胁方向交叉点
        elif threat_directions >= 2:
            strategic_bonus += 150
        
        # 综合评分
        total_score = (base_position_score + nearby_score + continuous_bonus + 
                      edge_penalty + corner_penalty + stage_adjustment + strategic_bonus)
        
        # 确保分数不为负
        return max(0, total_score)
    
    def _calculate_tactical_score(self, board: List[List[int]], row: int, col: int, player: int) -> int:
        """计算战术评分 - 超级增强版
        深度战术分析，包括阻断、拦截、战略位置、多方向威胁等高级战术考量
        
        Args:
            board: 当前棋盘
            row, col: 位置坐标
            player: 当前玩家
            
        Returns:
            战术评分
        """
        score = 0
        opponent = Constants.WHITE if player == Constants.BLACK else Constants.BLACK
        
        # 1. 高级阻断分析 - 更精确的对手威胁阻断评估
        for direction in [(0, 1), (1, 0), (1, 1), (1, -1)]:  # 四个方向
            dx, dy = direction
            opponent_count = 0
            left_empty = False
            right_empty = False
            blocked_left = False
            blocked_right = False
            
            # 向左/上方向检查
            for i in range(1, 6):  # 扩展检查范围到5步
                nx, ny = row - dx * i, col - dy * i
                if 0 <= nx < Constants.BOARD_SIZE and 0 <= ny < Constants.BOARD_SIZE:
                    if board[nx][ny] == opponent:
                        opponent_count += 1
                    elif board[nx][ny] == Constants.EMPTY:
                        left_empty = True
                        break
                    else:
                        blocked_left = True
                        break
                else:
                    blocked_left = True
                    break
            
            # 向右/下方向检查
            for i in range(1, 6):
                nx, ny = row + dx * i, col + dy * i
                if 0 <= nx < Constants.BOARD_SIZE and 0 <= ny < Constants.BOARD_SIZE:
                    if board[nx][ny] == opponent:
                        opponent_count += 1
                    elif board[nx][ny] == Constants.EMPTY:
                        right_empty = True
                        break
                    else:
                        blocked_right = True
                        break
                else:
                    blocked_right = True
                    break
            
            # 高级阻断价值评估
            if opponent_count >= 4:  # 对手有四连
                score += 5000  # 紧急阻断
            elif opponent_count == 3:
                # 分析是活三还是冲三
                if left_empty and right_empty:
                    score += 1200  # 阻断活三
                elif left_empty or right_empty:
                    score += 800   # 阻断冲三
            elif opponent_count == 2:
                if left_empty and right_empty:
                    score += 400   # 阻断活二
                elif (left_empty or right_empty) and (not blocked_left or not blocked_right):
                    score += 200   # 阻断潜在发展
        
        # 2. 潜在威胁创造分析 - 更深入的攻击可能性评估
        test_board = copy.deepcopy(board)
        test_board[row][col] = player
        
        # 分析落子后能形成的威胁类型
        created_threats = {
            'four_open': 0, 'four_semi': 0,
            'three_open': 0, 'three_semi': 0,
            'two_open': 0, 'two_semi': 0
        }
        
        for direction in [(0, 1), (1, 0), (1, 1), (1, -1)]:  # 四个方向
            dx, dy = direction
            player_count = 0
            left_empty = False
            right_empty = False
            blocked_left = False
            blocked_right = False
            
            # 向左/上方向检查
            for i in range(1, 5):
                nx, ny = row - dx * i, col - dy * i
                if 0 <= nx < Constants.BOARD_SIZE and 0 <= ny < Constants.BOARD_SIZE:
                    if test_board[nx][ny] == player:
                        player_count += 1
                    elif test_board[nx][ny] == Constants.EMPTY:
                        left_empty = True
                        break
                    else:
                        blocked_left = True
                        break
                else:
                    blocked_left = True
                    break
            
            # 向右/下方向检查
            for i in range(1, 5):
                nx, ny = row + dx * i, col + dy * i
                if 0 <= nx < Constants.BOARD_SIZE and 0 <= ny < Constants.BOARD_SIZE:
                    if test_board[nx][ny] == player:
                        player_count += 1
                    elif test_board[nx][ny] == Constants.EMPTY:
                        right_empty = True
                        break
                    else:
                        blocked_right = True
                        break
                else:
                    blocked_right = True
                    break
            
            # 识别创造的威胁类型
            if player_count >= 3:
                if left_empty and right_empty:
                    created_threats['four_open'] += 1
                elif left_empty or right_empty:
                    created_threats['four_semi'] += 1
            elif player_count == 2:
                if left_empty and right_empty:
                    created_threats['three_open'] += 1
                elif left_empty or right_empty:
                    created_threats['three_semi'] += 1
            elif player_count == 1:
                if left_empty and right_empty:
                    created_threats['two_open'] += 1
                elif left_empty or right_empty:
                    created_threats['two_semi'] += 1
        
        # 根据创造的威胁类型加分
        if created_threats['four_open'] >= 1:
            score += 8000  # 创建活四
        elif created_threats['four_semi'] >= 1:
            score += 4000  # 创建冲四
        elif created_threats['three_open'] >= 1:
            score += 2000  # 创建活三
        elif created_threats['three_semi'] >= 1:
            score += 1000  # 创建冲三
        
        # 威胁组合奖励
        total_threats_created = sum(created_threats.values())
        if total_threats_created >= 3:
            score += 3000  # 创造多个威胁
        elif total_threats_created >= 2:
            score += 1500
        
        # 3. 攻防平衡分析 - 更精确的战略位置评估
        # 评估对手在此位置的威胁潜力
        test_board[row][col] = opponent
        opponent_created_threats = {
            'four_open': 0, 'four_semi': 0,
            'three_open': 0, 'three_semi': 0
        }
        
        for direction in [(0, 1), (1, 0), (1, 1), (1, -1)]:  # 四个方向
            dx, dy = direction
            opp_count = 0
            left_empty = False
            right_empty = False
            
            # 向左/上方向检查
            for i in range(1, 5):
                nx, ny = row - dx * i, col - dy * i
                if 0 <= nx < Constants.BOARD_SIZE and 0 <= ny < Constants.BOARD_SIZE:
                    if test_board[nx][ny] == opponent:
                        opp_count += 1
                    elif test_board[nx][ny] == Constants.EMPTY:
                        left_empty = True
                        break
                    else:
                        break
            
            # 向右/下方向检查
            for i in range(1, 5):
                nx, ny = row + dx * i, col + dy * i
                if 0 <= nx < Constants.BOARD_SIZE and 0 <= ny < Constants.BOARD_SIZE:
                    if test_board[nx][ny] == opponent:
                        opp_count += 1
                    elif test_board[nx][ny] == Constants.EMPTY:
                        right_empty = True
                        break
                    else:
                        break
            
            # 识别对手潜在威胁类型
            if opp_count >= 3:
                if left_empty and right_empty:
                    opponent_created_threats['four_open'] += 1
                elif left_empty or right_empty:
                    opponent_created_threats['four_semi'] += 1
            elif opp_count == 2:
                if left_empty and right_empty:
                    opponent_created_threats['three_open'] += 1
                elif left_empty or right_empty:
                    opponent_created_threats['three_semi'] += 1
        
        # 4. 战略控制点奖励
        # 检查是否是关键的攻防转换点
        my_total = sum(created_threats.values())
        opp_total = sum(opponent_created_threats.values())
        
        if my_total >= 1 and opp_total >= 1:
            score += 1500  # 关键战略控制点
        
        # 5. 预测性战术分析 - 新增
        # 检查在此位置落子后，下一步是否能形成更高级别的威胁
        next_move_potential = 0
        
        # 模拟落子后，检查周围是否有潜在的下一步威胁点
        for dx in range(-2, 3):
            for dy in range(-2, 3):
                if dx == 0 and dy == 0:
                    continue
                
                next_x, next_y = row + dx, col + dy
                if 0 <= next_x < Constants.BOARD_SIZE and 0 <= next_y < Constants.BOARD_SIZE:
                    if test_board[next_x][next_y] == Constants.EMPTY:
                        # 检查这个下一步位置是否有形成高级威胁的潜力
                        next_test_board = copy.deepcopy(test_board)
                        next_test_board[next_x][next_y] = player
                        
                        # 简单评估下一步的威胁级别
                        next_threat_level = 0
                        for direction in [(0, 1), (1, 0), (1, 1), (1, -1)]:
                            ndx, ndy = direction
                            count = 0
                            
                            # 检查四个方向
                            for i in range(1, 5):
                                nx, ny = next_x + ndx * i, next_y + ndy * i
                                if 0 <= nx < Constants.BOARD_SIZE and 0 <= ny < Constants.BOARD_SIZE:
                                    if next_test_board[nx][ny] == player:
                                        count += 1
                                    else:
                                        break
                            
                            for i in range(1, 5):
                                nx, ny = next_x - ndx * i, next_y - ndy * i
                                if 0 <= nx < Constants.BOARD_SIZE and 0 <= ny < Constants.BOARD_SIZE:
                                    if next_test_board[nx][ny] == player:
                                        count += 1
                                    else:
                                        break
                            
                            if count >= 3:
                                next_threat_level = max(next_threat_level, 3)
                            elif count == 2:
                                next_threat_level = max(next_threat_level, 2)
                        
                        if next_threat_level >= 3:
                            next_move_potential += 1
        
        # 根据下一步威胁潜力加分
        if next_move_potential >= 2:
            score += 2000  # 多个潜在的下一步威胁
        elif next_move_potential >= 1:
            score += 1000  # 有潜在的下一步威胁
        
        # 6. 黑白棋策略差异化
        if player == Constants.BLACK:
            # 黑棋更注重进攻
            attack_factor = 1.3
            defense_factor = 1.0
        else:
            # 白棋更注重防守和平衡
            attack_factor = 1.0
            defense_factor = 1.2
        
        # 应用策略因子
        attack_score = (created_threats['four_open'] * 8000 + 
                       created_threats['four_semi'] * 4000 + 
                       created_threats['three_open'] * 2000 + 
                       created_threats['three_semi'] * 1000)
        
        defense_score = (opponent_created_threats['four_open'] * 8000 + 
                        opponent_created_threats['four_semi'] * 4000 + 
                        opponent_created_threats['three_open'] * 2000 + 
                        opponent_created_threats['three_semi'] * 1000)
        
        strategy_adjustment = (attack_score * attack_factor + defense_score * defense_factor)
        
        # 综合最终战术评分
        final_score = score + strategy_adjustment
        
        return int(final_score)
    
    def _select_best_move_from_candidates(self, board: List[List[int]], top_moves: list, player: int) -> Tuple[int, int]:
        """从候选位置中选择最佳落子点
        
        Args:
            board: 当前棋盘
            top_moves: 评分最高的候选位置列表
            player: 当前玩家
            
        Returns:
            最佳落子位置
        """
        # 如果只有一个候选，直接返回
        if len(top_moves) == 1:
            return (top_moves[0][1], top_moves[0][2])
        
        # 对候选位置进行更深入的评估
        refined_scores = []
        
        for score, i, j in top_moves:
            # 模拟落子并评估后续发展
            test_board = copy.deepcopy(board)
            test_board[i][j] = player
            
            # 1. 评估落子后的防守需求（对方的反击威胁）
            opponent = Constants.WHITE if player == Constants.BLACK else Constants.BLACK
            opponent_response_threat = 0
            
            # 检查对方可能的反击位置
            for dx in range(-2, 3):
                for dy in range(-2, 3):
                    nx, ny = i + dx, j + dy
                    if (0 <= nx < Constants.BOARD_SIZE and 
                        0 <= ny < Constants.BOARD_SIZE and 
                        test_board[nx][ny] == Constants.EMPTY):
                        test_board[nx][ny] = opponent
                        threat_level = self._evaluate_threat_level(test_board, nx, ny)
                        test_board[nx][ny] = Constants.EMPTY
                        
                        if threat_level >= 8:  # 对方反击形成冲四或更高威胁
                            opponent_response_threat += 1000
                        elif threat_level >= 6:  # 对方反击形成双三
                            opponent_response_threat += 500
                        elif threat_level >= 5:  # 对方反击形成活三
                            opponent_response_threat += 300
            
            # 2. 综合评分调整（减去对方可能的反击威胁）
            adjusted_score = score - opponent_response_threat
            refined_scores.append((adjusted_score, i, j))
        
        # 按调整后的评分排序
        refined_scores.sort(reverse=True, key=lambda x: x[0])
        
        return (refined_scores[0][1], refined_scores[0][2])
    
    def _evaluate_threat_level(self, board: List[List[int]], row: int, col: int) -> int:
        """评估指定位置落子后的威胁级别 - 增强版
        
        Args:
            board: 当前棋盘状态
            row, col: 要评估的位置
            
        Returns:
            威胁级别：
            10: 五子连珠（必胜）
            9: 活四（两端开口的四连子，必胜）
            8: 冲四（一端开口的四连子，威胁极大）
            7: 双四（同时形成两个四连子，包括活四和冲四的组合）
            6: 双三（两个活三，黑棋必胜）
            5: 活三（两端开口的三连子）
            4: 冲三（一端开口的三连子）
            3: 双二（两个活二）
            2: 活二（两端开口的两连子）
            1: 单连子或其他低威胁情况
            0: 无威胁
        """
        player = board[row][col]
        if player == Constants.EMPTY:
            return 0
            
        directions = [(0, 1), (1, 0), (1, 1), (1, -1)]
        
        # 检查是否已经赢了
        if self._check_win_in_board(board, row, col):
            return 10
        
        # 统计各威胁级别的数量
        threats = {
            'four_open': 0,    # 活四
            'four_semi': 0,    # 冲四
            'three_open': 0,   # 活三
            'three_semi': 0,   # 冲三
            'two_open': 0,     # 活二
            'two_semi': 0      # 半活二（一端开口的两连子）
        }
        
        # 检查各方向的威胁
        for dx, dy in directions:
            # 使用新的分析方法获取更详细的威胁信息
            threat_info = self._analyze_line_threat(board, row, col, dx, dy, player)
            if threat_info['type'] in threats:
                threats[threat_info['type']] += 1
        
        # 计算总威胁数用于组合威胁判断
        total_fours = threats['four_open'] + threats['four_semi']
        total_threes = threats['three_open'] + threats['three_semi']
        total_twos = threats['two_open'] + threats['two_semi']
        
        # 综合评估：高级威胁优先
        # 双四威胁（更精确的判断）
        if total_fours >= 2:
            return 7
        # 活四
        elif threats['four_open'] > 0:
            return 9
        # 冲四
        elif threats['four_semi'] > 0:
            return 8
        # 双三威胁（更精确的判断）
        elif total_threes >= 2:
            return 6
        # 活三
        elif threats['three_open'] > 0:
            return 5
        # 冲三
        elif threats['three_semi'] > 0:
            return 4
        # 双二威胁
        elif total_twos >= 2:
            return 3
        # 活二
        elif threats['two_open'] > 0:
            return 2
        # 半活二
        elif threats['two_semi'] > 0:
            return 1
        
        return 0
    
    def _analyze_line_threat(self, board: List[List[int]], row: int, col: int, dx: int, dy: int, player: int) -> dict:
        """深入分析指定方向上的威胁情况
        
        Args:
            board: 当前棋盘状态
            row, col: 起始位置
            dx, dy: 方向向量
            player: 玩家标识
            
        Returns:
            包含威胁类型和详细信息的字典
        """
        result = {'type': 'none', 'length': 0}
        
        # 计算该方向的连续棋子和空格情况
        left_empty = right_empty = False
        left_blocked = right_blocked = False
        left_count = right_count = 0
        
        # 正方向（更远的检查，以发现更多潜在威胁）
        for i in range(1, 6):  # 最多检查5步
            nx, ny = row + i * dx, col + i * dy
            if not (0 <= nx < Constants.BOARD_SIZE and 0 <= ny < Constants.BOARD_SIZE):
                right_blocked = True
                break
            if board[nx][ny] == player:
                right_count += 1
            elif board[nx][ny] == Constants.EMPTY:
                # 检查开口后面是否有空位可以形成更长的连续
                right_empty = True
                # 额外检查开口后的情况，看是否有形成更长连续的潜力
                additional_check = False
                nnx, nny = nx + dx, ny + dy
                if (0 <= nnx < Constants.BOARD_SIZE and 0 <= nny < Constants.BOARD_SIZE and 
                    board[nnx][nny] == player):
                    additional_check = True
                break
            else:
                right_blocked = True
                break
        
        # 反方向
        for i in range(1, 6):  # 最多检查5步
            nx, ny = row - i * dx, col - i * dy
            if not (0 <= nx < Constants.BOARD_SIZE and 0 <= ny < Constants.BOARD_SIZE):
                left_blocked = True
                break
            if board[nx][ny] == player:
                left_count += 1
            elif board[nx][ny] == Constants.EMPTY:
                left_empty = True
                break
            else:
                left_blocked = True
                break
        
        # 总长度（包括当前位置）
        total_count = left_count + right_count + 1
        
        # 判断威胁级别，更精确地识别各种威胁类型
        if total_count >= 4:
            if left_empty and right_empty:
                result['type'] = 'four_open'  # 活四
            elif left_empty or right_empty:
                result['type'] = 'four_semi'  # 冲四
        elif total_count == 3:
            if left_empty and right_empty:
                result['type'] = 'three_open'  # 活三
            elif left_empty or right_empty:
                result['type'] = 'three_semi'  # 冲三
        elif total_count == 2:
            if left_empty and right_empty:
                result['type'] = 'two_open'  # 活二
            elif left_empty or right_empty:
                result['type'] = 'two_semi'  # 半活二
        
        result['length'] = total_count
        return result
    
    def _check_win_in_board(self, board: List[List[int]], row: int, col: int) -> bool:
        """检查指定棋盘上以(row, col)为起点是否有五子连珠"""
        player = board[row][col]
        directions = [(0, 1), (1, 0), (1, 1), (1, -1)]
        
        for dx, dy in directions:
            count = 1
            # 正方向
            for i in range(1, Constants.WIN_LENGTH):
                nx, ny = row + i * dx, col + i * dy
                if not (0 <= nx < Constants.BOARD_SIZE and 0 <= ny < Constants.BOARD_SIZE) or board[nx][ny] != player:
                    break
                count += 1
            # 反方向
            for i in range(1, Constants.WIN_LENGTH):
                nx, ny = row - i * dx, col - i * dy
                if not (0 <= nx < Constants.BOARD_SIZE and 0 <= ny < Constants.BOARD_SIZE) or board[nx][ny] != player:
                    break
                count += 1
            
            if count >= Constants.WIN_LENGTH:
                return True
        return False

# ============== 用户交互模块 ==============
class GameUI:
    """游戏界面类（命令行版本）"""
    def __init__(self):
        self.board_manager = BoardManager()
        self.ai_player = AIPlayer(AIDifficulty.MEDIUM)
        self.player_color = Constants.BLACK  # 默认玩家执黑
        self.ai_color = Constants.WHITE
    
    def start_game(self):
        """开始游戏"""
        self._show_welcome()
        self._setup_game()
        self._game_loop()
    
    def _show_welcome(self):
        """显示欢迎信息"""
        print("=" * 50)
        print("            五子棋人机对弈系统")
        print("        MCTS与神经网络结合的AI引擎")
        print("=" * 50)
        print("规则：连成五子即为胜利！")
        print("操作：输入坐标（如：7 7）进行落子，输入'undo'悔棋，输入'quit'退出游戏")
        print()
    
    def _setup_game(self):
        """游戏设置"""
        # 选择玩家颜色
        while True:
            choice = input("请选择棋子颜色（1: 黑色，2: 白色）: ").strip()
            if choice == '1':
                self.player_color = Constants.BLACK
                self.ai_color = Constants.WHITE
                break
            elif choice == '2':
                self.player_color = Constants.WHITE
                self.ai_color = Constants.BLACK
                break
            else:
                print("输入无效，请重新选择！")
        
        # 选择AI难度
        print("请选择AI难度：")
        print("1. 简单")
        print("2. 中等")
        print("3. 困难")
        print("4. 专家")
        print("5. 大师")
        
        while True:
            choice = input("请选择难度等级（1-5）: ").strip()
            if choice in ['1', '2', '3', '4', '5']:
                difficulty = AIDifficulty(int(choice))
                self.ai_player.set_difficulty(difficulty)
                print(f"已选择{difficulty.name}难度")
                break
            else:
                print("输入无效，请重新选择！")
    
    def _game_loop(self):
        """游戏主循环"""
        self.board_manager.reset()
        
        # 如果AI执黑，先让AI落子
        if self.ai_color == Constants.BLACK:
            self._ai_move()
            self._display_board()
        
        while self.board_manager.game_status == Constants.PLAYING:
            # 玩家回合
            if not self._player_move():
                continue
            
            self._display_board()
            
            # 检查游戏状态
            if self.board_manager.game_status != Constants.PLAYING:
                break
            
            # AI回合
            print("AI正在思考...")
            self._ai_move()
            self._display_board()
        
        # 显示游戏结果
        self._show_result()
    
    def _player_move(self) -> bool:
        """玩家落子"""
        while True:
            move = input(f"请输入落子位置（行 列），或输入命令: ").strip().lower()
            
            # 处理特殊命令
            if move == 'quit':
                self.board_manager.game_status = Constants.DRAW
                return True
            elif move == 'undo':
                # 需要撤销两步（自己和AI的）
                if self.board_manager.undo_move():
                    if self.board_manager.current_player != self.player_color:
                        self.board_manager.undo_move()
                    print("已撤销一步")
                    self._display_board()
                else:
                    print("无法撤销")
                return False
            
            # 解析坐标
            try:
                row, col = map(int, move.split())
                # 转换为0-based索引
                row -= 1
                col -= 1
                
                if self.board_manager.make_move(row, col):
                    return True
                else:
                    print("无效的落子位置，请重新输入！")
            except ValueError:
                print("输入格式错误，请输入'行 列'格式！")
    
    def _ai_move(self):
        """AI落子"""
        board = self.board_manager.get_board_copy()
        row, col = self.ai_player.find_best_move(board, self.ai_color)
        self.board_manager.make_move(row, col)
        print(f"AI落子于：{row+1} {col+1}")
    
    def _display_board(self):
        """显示棋盘"""
        print("  ", end="")
        for i in range(1, Constants.BOARD_SIZE + 1):
            print(f"{i:2}", end=" ")
        print()
        
        for i in range(Constants.BOARD_SIZE):
            print(f"{i+1:2}", end=" ")
            for j in range(Constants.BOARD_SIZE):
                if self.board_manager.board[i][j] == Constants.EMPTY:
                    print(". ", end="")
                elif self.board_manager.board[i][j] == Constants.BLACK:
                    print("X ", end="")
                else:
                    print("O ", end="")
            print()
        print()
    
    def _show_result(self):
        """显示游戏结果"""
        if self.board_manager.game_status == Constants.BLACK_WIN:
            if self.player_color == Constants.BLACK:
                print("恭喜，你赢了！")
            else:
                print("AI赢了！")
        elif self.board_manager.game_status == Constants.WHITE_WIN:
            if self.player_color == Constants.WHITE:
                print("恭喜，你赢了！")
            else:
                print("AI赢了！")
        elif self.board_manager.game_status == Constants.DRAW:
            print("游戏结束，平局！")
        
        # 询问是否重新开始
        play_again = input("是否重新开始游戏？(y/n): ").strip().lower()
        if play_again == 'y':
            self.start_game()
        else:
            print("谢谢游玩！")

# ============== 主程序 ==============
if __name__ == "__main__":
    try:
        game = GameUI()
        game.start_game()
    except KeyboardInterrupt:
        print("\n游戏已退出")
    except Exception as e:
        print(f"发生错误: {e}")
